home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume10 / comobj.lisp / part09 < prev    next >
Encoding:
Text File  |  1987-08-01  |  35.2 KB  |  933 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i083:  Common Objects, Common Loops, Common Lisp, Part09/13
  5. Message-ID: <752@uunet.UU.NET>
  6. Date: 3 Aug 87 03:03:36 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 922
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: Roy D'Souza <dsouza%hplabsc@hplabs.HP.COM>
  12. Posting-number: Volume 10, Issue 83
  13. Archive-name: comobj.lisp/Part09
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 9 (of 13)."
  22. # Contents:  walk.l
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'walk.l' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'walk.l'\"
  26. else
  27. echo shar: Extracting \"'walk.l'\" \(33372 characters\)
  28. sed "s/^X//" >'walk.l' <<'END_OF_FILE'
  29. X;;;-*- Mode:LISP; Package:(WALKER LISP 1000); Base:10; Syntax:Common-lisp -*-
  30. X;;;
  31. X;;; *************************************************************************
  32. X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
  33. X;;;
  34. X;;; Use and copying of this software and preparation of derivative works
  35. X;;; based upon this software are permitted.  Any distribution of this
  36. X;;; software or derivative works must comply with all applicable United
  37. X;;; States export control laws.
  38. X;;; 
  39. X;;; This software is made available AS IS, and Xerox Corporation makes no
  40. X;;; warranty about the software, its performance or its conformity to any
  41. X;;; specification.
  42. X;;; 
  43. X;;; Any person obtaining a copy of this software is requested to send their
  44. X;;; name and post office or electronic mail address to:
  45. X;;;   CommonLoops Coordinator
  46. X;;;   Xerox Artifical Intelligence Systems
  47. X;;;   2400 Hanover St.
  48. X;;;   Palo Alto, CA 94303
  49. X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  50. X;;;
  51. X;;; Suggestions, comments and requests for improvements are also welcome.
  52. X;;; *************************************************************************
  53. X;;; 
  54. X;;; A simple code walker, based IN PART on: (roll the credits)
  55. X;;;   Larry Masinter's Masterscope
  56. X;;;   Moon's Common Lisp code walker
  57. X;;;   Gary Drescher's code walker
  58. X;;;   Larry Masinter's simple code walker
  59. X;;;   .
  60. X;;;   .
  61. X;;;   boy, thats fair (I hope).
  62. X;;;
  63. X;;; For now at least, this code walker really only does what PCL needs it to
  64. X;;; do.  Maybe it will grow up someday.
  65. X;;;
  66. X
  67. X(in-package 'walker)
  68. X
  69. X(export '(define-walker-template
  70. X      walk-form
  71. X      variable-lexical-p
  72. X      variable-special-p
  73. X      ))
  74. X
  75. X;;; *walk-function* is the function being called on each sub-form as we walk.
  76. X;;; Normally it is supplied using the :walk-function keyword argument to
  77. X;;; walk-form, but it is OK to bind it around a call to walk-form-internal.
  78. X(defvar *walk-function*)
  79. X
  80. X;;; *walk-form* is used by the IF template.  When the first argument to the
  81. X;;; if template is a list it will be evaluated with *walk-form* bound to the 
  82. X;;; form currently being walked.
  83. X(defvar *walk-form*)
  84. X
  85. X;;; *declarations* is a list of the declarations currently in effect.
  86. X(defvar *declarations*)
  87. X    
  88. X;;; *lexical-variables* is a list of the variables bound in the current
  89. X;;; contour. In *lexical-variables* the cons whose car is the variable is
  90. X;;; meaningful in the sense that the cons whose car is the variable can be
  91. X;;; used to keep track of which contour the variable is bound in.
  92. X;;;
  93. X;;; Now isn't that just the cats pajamas.
  94. X;;;
  95. X(defvar *lexical-variables*)
  96. X
  97. X;;; An environment of the kind that macroexpand-1 gets as its second
  98. X;;; argument.  In fact, that is exactly where it comes from.  This is kind of
  99. X;;; kludgy since Common Lisp is somewhat screwed up in this respect.
  100. X;;; Hopefully Common Lisp will fix this soon.  For more info see:
  101. X;;; MAKE-LEXICAL-ENVIRONMENT
  102. X(defvar *environment*)
  103. X
  104. X;;;
  105. X;;; With new contour is used to enter a new lexical binding contour which
  106. X;;; inherits from the exisiting one.  I admit that using with-new-contour is
  107. X;;; often overkill.  It would suffice for the the walker to rebind
  108. X;;; *lexical-variables* and *declarations* when walking LET and rebind
  109. X;;; *environment* and *declarations* when walking MACROLET etc.
  110. X;;; WITH-NEW-CONTOUR is much more convenient and just as correct.
  111. X;;; 
  112. X(defmacro with-new-contour (&body body)
  113. X  `(let ((*declarations* ())            ;If Common Lisp got an
  114. X                        ;unspecial declaration
  115. X                        ;this would need to be
  116. X                        ;re-worked.
  117. X         (*lexical-variables* *lexical-variables*)
  118. X         (*environment* *environment*))
  119. X     . ,body))
  120. X
  121. X(defmacro note-lexical-binding (thing)
  122. X  `(push ,thing *lexical-variables*))
  123. X
  124. X(defmacro note-declaration (declaration)
  125. X  `(push ,declaration *declarations*))
  126. X
  127. X
  128. X(defun variable-lexically-boundp (var)
  129. X  (if (not (boundp '*walk-function*))
  130. X      :unsure
  131. X      (values (member var *lexical-variables* :test (function eq))
  132. X          (variable-special-p var) 't)))
  133. X
  134. X(defun variable-lexical-p (var)
  135. X  (if (not (boundp '*walk-function*))
  136. X      :unsure
  137. X      (and (not (eq (variable-special-p var) 't))
  138. X       (member var *lexical-variables* :test (function eq)))))
  139. X
  140. X(defun variable-special-p (var)
  141. X  (if (not (boundp '*walk-function*))
  142. X      (or (variable-globally-special-p var) :unsure)
  143. X      (or (dolist (decl *declarations*)
  144. X        (and (eq (car decl) 'special)
  145. X         (member var (cdr decl) :test #'eq)
  146. X         (return t)))
  147. X      (variable-globally-special-p var))))
  148. X
  149. X;;;
  150. X;;; VARIABLE-GLOBALLY-SPECIAL-P is used to ask if a variable has been
  151. X;;; declared globally special.  Any particular CommonLisp implementation
  152. X;;; should customize this function accordingly and send their customization
  153. X;;; back.
  154. X;;;
  155. X;;; The default version of variable-globally-special-p is probably pretty
  156. X;;; slow, so it uses *globally-special-variables* as a cache to remember
  157. X;;; variables that it has already figured out are globally special.
  158. X;;;
  159. X;;; This would need to be reworked if an unspecial declaration got added to
  160. X;;; Common Lisp.
  161. X;;;
  162. X;;; Common Lisp nit:
  163. X;;;   variable-globally-special-p should be defined in Common Lisp.
  164. X;;;
  165. X#-(or Symbolics Xerox TI VaxLisp KCL LMI excl)
  166. X(defvar *globally-special-variables* ())
  167. X
  168. X(defun variable-globally-special-p (symbol)
  169. X  #+Symbolics                   (si:special-variable-p symbol)
  170. X  #+(or Lucid TI LMI)           (get symbol 'special)
  171. X  #+Xerox                       (il:variable-globally-special-p symbol)
  172. X  #+VaxLisp                     (get symbol 'system::globally-special)
  173. X  #+KCL                    (si:specialp symbol)
  174. X  #+excl                        (get symbol 'excl::.globally-special.)
  175. X  #+HP                          (member (get symbol 'impl:vartype)
  176. X                    '(impl:fluid impl:global)
  177. X                    :test #'eq)
  178. X  #-(or Symbolics Lucid TI LMI Xerox VaxLisp KCL excl HP)
  179. X  (or (not (null (member symbol *globally-special-variables* :test #'eq)))
  180. X      (when (eval `(flet ((ref () ,symbol))
  181. X             (let ((,symbol '#,(list nil)))
  182. X               (and (boundp ',symbol) (eq ,symbol (ref))))))
  183. X    (push symbol *globally-special-variables*)
  184. X    t)))
  185. X
  186. X
  187. X  ;;   
  188. X;;;;;; Handling of special forms (the infamous 24).
  189. X  ;;
  190. X;;;
  191. X;;; and I quote...
  192. X;;; 
  193. X;;;     The set of special forms is purposely kept very small because
  194. X;;;     any program analyzing program (read code walker) must have
  195. X;;;     special knowledge about every type of special form. Such a
  196. X;;;     program needs no special knowledge about macros...
  197. X;;;
  198. X;;; So all we have to do here is a define a way to store and retrieve
  199. X;;; templates which describe how to walk the 24 special forms and we are all
  200. X;;; set...
  201. X;;;
  202. X;;; Well, its a nice concept, and I have to admit to being naive enough that
  203. X;;; I believed it for a while, but not everyone takes having only 24 special
  204. X;;; forms as seriously as might be nice.  There are (at least) 3 ways to
  205. X;;; lose:
  206. X;;
  207. X;;;   1 - Implementation x implements a Common Lisp special form as a macro
  208. X;;;       which expands into a special form which:
  209. X;;;         - Is a common lisp special form (not likely)
  210. X;;;         - Is not a common lisp special form (on the 3600 IF --> COND).
  211. X;;;
  212. X;;;     * We can safe ourselves from this case (second subcase really) by
  213. X;;;       checking to see if there is a template defined for something
  214. X;;;       before we check to see if we we can macroexpand it.
  215. X;;;
  216. X;;;   2 - Implementation x implements a Common Lisp macro as a special form.
  217. X;;;
  218. X;;;     * This is a screw, but not so bad, we save ourselves from it by
  219. X;;;       defining extra templates for the macros which are *likely* to
  220. X;;;       be implemented as special forms.  (DO, DO* ...)
  221. X;;;
  222. X;;;   3 - Implementation x has a special form which is not on the list of
  223. X;;;       Common Lisp special forms.
  224. X;;;
  225. X;;;     * This is a bad sort of a screw and happens more than I would like
  226. X;;;       to think, especially in the implementations which provide more
  227. X;;;       than just Common Lisp (3600, Xerox etc.).
  228. X;;;       The fix is not terribly staisfactory, but will have to do for
  229. X;;;       now.  There is a hook in get walker-template which can get a
  230. X;;;       template from the implementation's own walker.  That template
  231. X;;;       has to be converted, and so it may be that the right way to do
  232. X;;;       this would actually be for that implementation to provide an
  233. X;;;       interface to its walker which looks like the interface to this
  234. X;;;       walker.
  235. X;;;
  236. X(defmacro get-walker-template-internal (x)
  237. X  `(get ,x 'walker-template))
  238. X
  239. X(defun get-walker-template (x)
  240. X  (cond ((symbolp x)
  241. X     (or (get-walker-template-internal x)
  242. X         (get-implementation-dependent-walker-template x)))
  243. X    ((and (listp x) (eq (car x) 'lambda))
  244. X     '(lambda repeat (eval)))
  245. X    ((and (listp x) (eq (car x) 'lambda))
  246. X     '(call repeat (eval)))))
  247. X
  248. X(defun get-implementation-dependent-walker-template (x)
  249. X  (declare (ignore x))
  250. X  ())
  251. X
  252. X(eval-when (compile load eval)
  253. X(defmacro define-walker-template (name template)
  254. X  `(eval-when (load eval)
  255. X     (setf (get-walker-template-internal ',name) ',template)))
  256. X)
  257. X
  258. X
  259. X  ;;   
  260. X;;;;;; The actual templates
  261. X  ;;   
  262. X
  263. X(define-walker-template BLOCK                (NIL NIL REPEAT (EVAL)))
  264. X(define-walker-template CATCH                (NIL EVAL REPEAT (EVAL)))
  265. X(define-walker-template COMPILER-LET         walk-compiler-let)
  266. X(define-walker-template DECLARE              walk-unexpected-declare)
  267. X(define-walker-template EVAL-WHEN            (NIL QUOTE REPEAT (EVAL)))
  268. X(define-walker-template FLET                 walk-flet/labels)
  269. X(define-walker-template FUNCTION             (NIL CALL))
  270. X(define-walker-template GO                   (NIL QUOTE))
  271. X(define-walker-template IF                   (NIL TEST RETURN RETURN))
  272. X(define-walker-template LABELS               walk-flet/labels)
  273. X(define-walker-template LAMBDA               walk-lambda)
  274. X(define-walker-template LET                  walk-let)
  275. X(define-walker-template LET*                 walk-let*)
  276. X(define-walker-template MACROLET             walk-macrolet)
  277. X(define-walker-template MULTIPLE-VALUE-CALL  (NIL EVAL REPEAT (EVAL)))
  278. X(define-walker-template MULTIPLE-VALUE-PROG1 (NIL RETURN REPEAT (EVAL)))
  279. X(define-walker-template MULTIPLE-VALUE-SETQ  (NIL (REPEAT (SET)) EVAL))
  280. X(define-walker-template PROGN                (NIL REPEAT (EVAL)))
  281. X(define-walker-template PROGV                (NIL EVAL EVAL REPEAT (EVAL)))
  282. X(define-walker-template QUOTE                (NIL QUOTE))
  283. X(define-walker-template RETURN-FROM          (NIL QUOTE REPEAT (RETURN)))
  284. X(define-walker-template SETQ                 (NIL REPEAT (SET EVAL)))
  285. X(define-walker-template TAGBODY              walk-tagbody)
  286. X(define-walker-template THE                  (NIL QUOTE EVAL))
  287. X(define-walker-template THROW                (NIL EVAL EVAL))
  288. X(define-walker-template UNWIND-PROTECT       (NIL RETURN REPEAT (EVAL)))
  289. X
  290. X;;; The new special form.
  291. X;(define-walker-template pcl::LOAD-TIME-EVAL       (NIL EVAL))
  292. X
  293. X;;;
  294. X;;; And the extra templates...
  295. X;;;
  296. X(define-walker-template DO      walk-do)
  297. X(define-walker-template DO*     walk-do*)
  298. X(define-walker-template PROG    walk-let)
  299. X(define-walker-template PROG*   walk-let*)
  300. X(define-walker-template COND    (NIL REPEAT ((TEST REPEAT (EVAL)))))
  301. X
  302. X
  303. X  ;;   
  304. X;;;;;; WALK-FORM
  305. X  ;;   
  306. X;;;
  307. X;;; The main entry-point is walk-form, calls back in should use walk-form-internal.
  308. X;;; 
  309. X
  310. X(defun walk-form (form &key ((:declarations *declarations*) ())
  311. X                ((:lexical-variables *lexical-variables*) ())
  312. X                ((:environment *environment*) ())
  313. X                ((:walk-function *walk-function*) #'(lambda (x y)
  314. X                                  y x)))
  315. X  (walk-form-internal form 'eval))
  316. X
  317. X;;;
  318. X;;; WALK-FORM-INTERNAL is the main driving function for the code walker. It
  319. X;;; takes a form and the current context and walks the form calling itself or
  320. X;;; the appropriate template recursively.
  321. X;;;
  322. X;;;   "It is recommended that a program-analyzing-program process a form
  323. X;;;    that is a list whose car is a symbol as follows:
  324. X;;;
  325. X;;;     1. If the program has particular knowledge about the symbol,
  326. X;;;        process the form using special-purpose code.  All of the
  327. X;;;        standard special forms should fall into this category.
  328. X;;;     2. Otherwise, if macro-function is true of the symbol apply
  329. X;;;        either macroexpand or macroexpand-1 and start over.
  330. X;;;     3. Otherwise, assume it is a function call. "
  331. X;;;     
  332. X
  333. X(defun walk-form-internal (form context
  334. X               &aux newform newnewform
  335. X                walk-no-more-p macrop
  336. X                fn template)
  337. X  ;; First apply the *walk-function* to perform whatever translation
  338. X  ;; the user wants to to this form.  If the second value returned
  339. X  ;; by *walk-function* is T then we don't recurse...
  340. X  (multiple-value-setq (newform walk-no-more-p)
  341. X    (funcall *walk-function* form context))
  342. X  (cond (walk-no-more-p newform)
  343. X    ((not (eq form newform)) (walk-form-internal newform context))
  344. X    ((not (consp newform)) newform)
  345. X    ((setq template (get-walker-template (setq fn (car newform))))
  346. X         (if (symbolp template)
  347. X             (funcall template newform context)
  348. X             (walk-template newform template context)))
  349. X    ((progn (multiple-value-setq (newnewform macrop)
  350. X          (macroexpand-1 newform *environment*))
  351. X        macrop)
  352. X     (walk-form-internal newnewform context))
  353. X    ((and (symbolp fn)
  354. X          (not (fboundp fn))
  355. X          (special-form-p fn))
  356. X     (error
  357. X       "~S is a special form, not defined in the CommonLisp manual.~%~
  358. X            This code walker doesn't know how to walk it.  Please define a~%~
  359. X            template for this special form and try again."
  360. X       fn))
  361. X    (t
  362. X         ;; Otherwise, walk the form as if its just a standard function
  363. X         ;; call using a template for standard function call.
  364. X         (walk-template newform '(call repeat (eval)) context))))
  365. X
  366. X(defun walk-template (form template context)
  367. X  (if (atom template)
  368. X      (ecase template
  369. X        ((QUOTE NIL) form)
  370. X        ((EVAL FUNCTION TEST EFFECT RETURN)
  371. X         (walk-form-internal form :EVAL))
  372. X        (SET
  373. X          (walk-form-internal form :SET))
  374. X        ((LAMBDA CALL)
  375. X     (if (symbolp form)
  376. X         form
  377. X         (walk-lambda form context))))
  378. X      (case (car template)
  379. X        (IF
  380. X          (let ((*walk-form* form))
  381. X            (walk-template form
  382. X               (if (if (listp (cadr template))
  383. X                   (eval (cadr template))
  384. X                   (funcall (cadr template) form))
  385. X                   (caddr template)
  386. X                   (cadddr template))
  387. X               context)))
  388. X        (REPEAT
  389. X          (walk-template-handle-repeat form
  390. X                                       (cdr template)
  391. X                       ;; For the case where nothing happens
  392. X                       ;; after the repeat optimize out the
  393. X                       ;; call to length.
  394. X                       (if (null (cddr template))
  395. X                       ()
  396. X                       (nthcdr (- (length form)
  397. X                              (length
  398. X                            (cddr template)))
  399. X                           form))
  400. X                                       context))
  401. X        (REMOTE
  402. X          (walk-template form (cadr template) context))
  403. X        (otherwise
  404. X          (cond ((atom form) form)
  405. X                (t (recons form
  406. X                           (walk-template
  407. X                 (car form) (car template) context)
  408. X                           (walk-template
  409. X                 (cdr form) (cdr template) context))))))))
  410. X
  411. X(defun walk-template-handle-repeat (form template stop-form context)
  412. X  (if (eq form stop-form)
  413. X      (walk-template form (cdr template) context)
  414. X      (walk-template-handle-repeat-1 form
  415. X                     template
  416. X                     (car template)
  417. X                     stop-form
  418. X                     context)))
  419. X
  420. X(defun walk-template-handle-repeat-1 (form template repeat-template
  421. X                       stop-form context)
  422. X  (cond ((null form) ())
  423. X        ((eq form stop-form)
  424. X         (if (null repeat-template)
  425. X             (walk-template stop-form (cdr template) context)       
  426. X             (error "While handling repeat:
  427. X                     ~%~Ran into stop while still in repeat template.")))
  428. X        ((null repeat-template)
  429. X         (walk-template-handle-repeat-1
  430. X       form template (car template) stop-form context))
  431. X        (t
  432. X         (recons form
  433. X                 (walk-template (car form) (car repeat-template) context)
  434. X                 (walk-template-handle-repeat-1 (cdr form)
  435. X                        template
  436. X                        (cdr repeat-template)
  437. X                        stop-form
  438. X                        context)))))
  439. X
  440. X(defun recons (x car cdr)
  441. X  (if (or (not (eq (car x) car))
  442. X          (not (eq (cdr x) cdr)))
  443. X      (cons car cdr)
  444. X      x))
  445. X
  446. X(defun relist* (x &rest args)
  447. X  (relist*-internal x args))
  448. X
  449. X(defun relist*-internal (x args)
  450. X  (if (null (cdr args))
  451. X      (car args)
  452. X      (recons x (car args) (relist*-internal (cdr x) (cdr args)))))
  453. X
  454. X
  455. X  ;;   
  456. X;;;;;; Special walkers
  457. X  ;;
  458. X
  459. X(defun walk-declarations (body fn
  460. X                   &optional doc-string-p declarations old-body
  461. X                   &aux (form (car body)))
  462. X  (cond ((and (stringp form)            ;might be a doc string
  463. X              (cdr body)            ;isn't the returned value
  464. X              (null doc-string-p)        ;no doc string yet
  465. X              (null declarations))        ;no declarations yet
  466. X         (recons body
  467. X                 form
  468. X                 (walk-declarations (cdr body) fn t)))
  469. X        ((and (listp form) (eq (car form) 'declare))
  470. X         ;; Got ourselves a real live declaration.  Record it, look for more.
  471. X         (dolist (declaration (cdr form))
  472. X           (note-declaration declaration)
  473. X           (push declaration declarations))
  474. X         (recons body
  475. X                 form
  476. X                 (walk-declarations
  477. X           (cdr body) fn doc-string-p declarations)))
  478. X        ((and form
  479. X          (listp form)
  480. X          (null (get-walker-template (car form)))
  481. X          (not (eq form (setq form (macroexpand-1 form *environment*)))))
  482. X         ;; When we macroexpanded this form we got something else back.
  483. X         ;; Maybe this is a macro which expanded into a declare?
  484. X     ;; Recurse to find out.
  485. X         (walk-declarations
  486. X       (cons form (cdr body)) fn doc-string-p declarations (or old-body
  487. X                                   body)))
  488. X        (t
  489. X         ;; Now that we have walked and recorded the declarations, call the
  490. X     ;; function our caller provided to expand the body.  We call that
  491. X     ;; function rather than passing the real-body back, because we are
  492. X     ;; RECONSING up the new body.
  493. X         (funcall fn (or old-body body)))))
  494. X
  495. X(defun fix-lucid-1.2 (x) x)
  496. X
  497. X(defun walk-unexpected-declare (form context)
  498. X  (declare (ignore context))
  499. X  (warn "Encountered declare ~S in a place where a declare was not expected."
  500. X    form)
  501. X  form)
  502. X
  503. X(defun walk-arglist (arglist context &optional (destructuringp nil) &aux arg)
  504. X  (cond ((null arglist) ())
  505. X        ((symbolp (setq arg (car arglist)))
  506. X         (or (member arg lambda-list-keywords :test #'eq)
  507. X             (note-lexical-binding arg))
  508. X         (recons arglist
  509. X                 arg
  510. X                 (walk-arglist (cdr arglist)
  511. X                               context
  512. X                               (and destructuringp
  513. X                    (not (member arg lambda-list-keywords
  514. X                         :test #'eq))))))
  515. X        ((consp arg)
  516. X         (prog1 (if destructuringp
  517. X                    (walk-arglist arg context destructuringp)
  518. X                    (recons arglist
  519. X                            (relist* arg
  520. X                                     (car arg)
  521. X                                     (walk-form-internal (cadr arg) 'eval)
  522. X                                     (cddr arg))
  523. X                            (walk-arglist (cdr arglist) context nil)))
  524. X                (if (symbolp (car arg))
  525. X                    (note-lexical-binding (car arg))
  526. X                    (note-lexical-binding (cadar arg)))
  527. X                (or (null (cddr arg))
  528. X                    (not (symbolp (caddr arg)))
  529. X                    (note-lexical-binding arg))))
  530. X          (t
  531. X       (error "Can't understand something in the arglist ~S" arglist))))
  532. X
  533. X(defun walk-let (form context)
  534. X  (walk-let/let* form context nil))
  535. X
  536. X(defun walk-let* (form context)
  537. X  (walk-let/let* form context t))
  538. X
  539. X(defun walk-do (form context)
  540. X  (walk-do/do* form context nil))
  541. X
  542. X(defun walk-do* (form context)
  543. X  (walk-do/do* form context t))
  544. X
  545. X(defun walk-let/let* (form context sequentialp)
  546. X  (let ((old-declarations *declarations*)
  547. X    (old-lexical-variables *lexical-variables*))
  548. X    (with-new-contour
  549. X      (let* ((let/let* (car form))
  550. X             (bindings (cadr form))
  551. X             (body (cddr form))
  552. X             walked-bindings
  553. X             (walked-body
  554. X               (walk-declarations 
  555. X                 body
  556. X                 #'(lambda (real-body)
  557. X                     (setq walked-bindings
  558. X                           (walk-bindings-1 bindings
  559. X                        old-declarations
  560. X                        old-lexical-variables
  561. X                        context
  562. X                        sequentialp))
  563. X                     (walk-template real-body '(repeat (eval)) context)))))
  564. X        (relist*
  565. X      form let/let* (fix-lucid-1.2 walked-bindings) walked-body)))))
  566. X
  567. X(defun walk-do/do* (form context sequentialp)
  568. X  (let ((old-declarations *declarations*)
  569. X    (old-lexical-variables *lexical-variables*))
  570. X    (with-new-contour
  571. X      (let* ((do/do* (car form))
  572. X             (bindings (cadr form))
  573. X             (end-test (caddr form))
  574. X             (body (cdddr form))
  575. X             walked-bindings
  576. X             (walked-body
  577. X               (walk-declarations
  578. X                 body
  579. X                 #'(lambda (real-body)
  580. X                     (setq walked-bindings
  581. X                           (walk-bindings-1 bindings
  582. X                        old-declarations
  583. X                        old-lexical-variables
  584. X                        context
  585. X                        sequentialp))
  586. X                     (walk-template real-body '(repeat (eval)) context)))))
  587. X        (relist* form
  588. X                 do/do*
  589. X                 (walk-bindings-2 bindings walked-bindings context)
  590. X                 (walk-template end-test '(test repeat (eval)) context)
  591. X                 walked-body)))))
  592. X                            
  593. X(defun walk-bindings-1 (bindings old-declarations old-lexical-variables
  594. X                 context sequentialp)
  595. X  (and bindings
  596. X       (let ((binding (car bindings)))
  597. X         (recons bindings
  598. X                 (if (symbolp binding)
  599. X                     (prog1 binding
  600. X                            (note-lexical-binding binding))
  601. X                     (prog1 (let ((*declarations* old-declarations)
  602. X                  (*lexical-variables*
  603. X                    (if sequentialp
  604. X                    *lexical-variables*
  605. X                    old-lexical-variables)))
  606. X                              (relist* binding
  607. X                                       (car binding)
  608. X                                       (walk-form-internal (cadr binding)
  609. X                               context)
  610. X                                       (cddr binding)))    ;save cddr for DO/DO*
  611. X                                ;it is the next value
  612. X                                ;form. Don't walk it
  613. X                                ;now though.
  614. X                            (note-lexical-binding (car binding))))
  615. X                 (walk-bindings-1 (cdr bindings)
  616. X                  old-declarations old-lexical-variables
  617. X                  context sequentialp)))))
  618. X
  619. X(defun walk-bindings-2 (bindings walked-bindings context)
  620. X  (and bindings
  621. X       (let ((binding (car bindings))
  622. X             (walked-binding (car walked-bindings)))
  623. X         (recons bindings
  624. X         (if (symbolp binding)
  625. X             binding
  626. X             (relist* binding
  627. X                  (car walked-binding)
  628. X                  (cadr walked-binding)
  629. X                  (walk-template (cddr binding) '(eval) context)))         
  630. X                 (walk-bindings-2 (cdr bindings)
  631. X                  (cdr walked-bindings)
  632. X                  context)))))
  633. X
  634. X(defun walk-lambda (form context)
  635. X  (with-new-contour    
  636. X    (let* ((arglist (cadr form))
  637. X           (body (cddr form))
  638. X           (walked-arglist nil)
  639. X           (walked-body
  640. X             (walk-declarations body
  641. X           #'(lambda (real-body)
  642. X           (setq walked-arglist (walk-arglist arglist context))
  643. X           (walk-template real-body '(repeat (eval)) context)))))
  644. X      (relist* form
  645. X               (car form)
  646. X               (fix-lucid-1.2 walked-arglist)
  647. X               walked-body))))
  648. X
  649. X(defun walk-tagbody (form context)
  650. X  (recons form (car form) (walk-tagbody-1 (cdr form) context)))
  651. X
  652. X(defun walk-tagbody-1 (form context)
  653. X  (and form
  654. X       (recons form
  655. X               (walk-form-internal (car form)
  656. X                   (if (symbolp (car form)) 'quote context))
  657. X               (walk-tagbody-1 (cdr form) context))))
  658. X
  659. X(defun walk-compiler-let (form context)
  660. X  (with-new-contour
  661. X    (let ((vars ())
  662. X      (vals ()))
  663. X      (dolist (binding (cadr form))
  664. X    (cond ((symbolp binding) (push binding vars) (push nil vals))
  665. X          (t
  666. X           (push (car binding) vars)
  667. X           (push (eval (cadr binding)) vals))))
  668. X      (relist* form
  669. X               (car form)
  670. X               (cadr form)
  671. X               (progv vars vals
  672. X                 (note-declaration (cons 'special vars))
  673. X                 (walk-template (cddr form) '(repeat (eval)) context))))))
  674. X
  675. X(defun walk-macrolet (form context)
  676. X  (labels ((walk-definitions (definitions)
  677. X             (and (not (null definitions))
  678. X                  (let ((definition (car definitions)))
  679. X                    (recons definitions
  680. X                            (with-new-contour
  681. X                              (relist* definition
  682. X                                       (car definition)
  683. X                                       (walk-arglist (cadr definition)
  684. X                             context t)
  685. X                                       (walk-declarations (cddr definition)
  686. X                     #'(lambda (real-body)
  687. X                         (walk-template
  688. X                           real-body
  689. X                           '(repeat (eval))
  690. X                           context)))))
  691. X                            (walk-definitions (cdr definitions)))))))
  692. X    (with-new-contour
  693. X      (relist* form
  694. X               (car form)
  695. X               (walk-definitions (cadr form))
  696. X               (progn (setq *environment*
  697. X                (make-lexical-environment form *environment*))
  698. X                      (walk-declarations (cddr form)
  699. X            #'(lambda (real-body)
  700. X                (walk-template real-body
  701. X                            '(repeat (eval))
  702. X                            context))))))))
  703. X
  704. X(defun walk-flet/labels (form context)
  705. X  (with-new-contour
  706. X    (labels ((walk-definitions (definitions)
  707. X               (if (null definitions)
  708. X                   ()
  709. X                   (recons definitions
  710. X                           (walk-lambda (car definitions) context)
  711. X                           (walk-definitions (cdr definitions)))))
  712. X             (update-environment ()
  713. X               (setq *environment*
  714. X             (make-lexical-environment form *environment*))))
  715. X      (relist* form
  716. X               (car form)
  717. X               (ecase (car form)
  718. X                 (flet
  719. X                   (prog1 (walk-definitions (cadr form))
  720. X                          (update-environment)))
  721. X                 (labels
  722. X                   (update-environment)
  723. X                   (walk-definitions (cadr form))))
  724. X               (walk-declarations (cddr form)
  725. X         #'(lambda (real-body)
  726. X             (walk-template real-body '(repeat (eval)) context)))))))
  727. X
  728. X;;; make-lexical-environemnt is kind of gross.  It would be less gross if
  729. X;;; EVAL took an environment argument.
  730. X;;;
  731. X;;; Common Lisp nit:
  732. X;;;    if Common Lisp should provide mechanisms for playing with
  733. X;;;    environments explicitly.  making them, finding out what
  734. X;;;    functions are bound in them etc.  Maybe compile should
  735. X;;;    take an environment argument too?
  736. X;;;    
  737. X
  738. X(defun make-lexical-environment (macrolet/flet/labels-form environment)
  739. X  (evalhook (list (car macrolet/flet/labels-form)
  740. X                  (cadr macrolet/flet/labels-form)
  741. X                  (list 'make-lexical-environment-2))
  742. X            'make-lexical-environment-1
  743. X            ()
  744. X            environment))
  745. X
  746. X(defun make-lexical-environment-1 (form env)
  747. X  (setq form (macroexpand form #-excl env
  748. X                   #+excl (cadr env)))
  749. X  (evalhook form  'make-lexical-environment-1 nil env))
  750. X
  751. X(defmacro make-lexical-environment-2 (&environment env)
  752. X  (list 'quote (copy-tree env)))
  753. X
  754. X  ;;   
  755. X;;;;;; Tests tests tests
  756. X  ;;
  757. X
  758. X#|
  759. X
  760. X(defmacro take-it-out-for-a-test-walk (form)
  761. X  `(progn 
  762. X     (terpri)
  763. X     (terpri)
  764. X     (let ((copy-of-form (copy-tree ',form))
  765. X           (result (walk-form ',form :walk-function
  766. X                              '(lambda (x y)
  767. X                                 (format t "~&Form: ~S ~3T Context: ~A" x y)
  768. X                                 (when (symbolp x)
  769. X                   (multiple-value-bind (lexical special)
  770. X                       (variable-lexically-boundp x)
  771. X                                     (when lexical
  772. X                                       (format t ";~3T")
  773. X                                       (format t "lexically bound"))
  774. X                                     (when special
  775. X                                       (format t ";~3T")
  776. X                                       (format t "declared special"))
  777. X                                     (when (boundp x)
  778. X                                       (format t ";~3T")
  779. X                                       (format t "bound: ~S " (eval x)))))
  780. X                                 x))))
  781. X       (cond ((not (equal result copy-of-form))
  782. X              (format t "~%Warning: Result not EQUAL to copy of start."))
  783. X             ((not (eq result ',form))
  784. X              (format t "~%Warning: Result not EQ to copy of start.")))
  785. X       (#+Symbolics zl:grind-top-level
  786. X        #-Symbolics print
  787. X                                  result)
  788. X       result)))
  789. X
  790. X(defun foo (&rest ignore) ())
  791. X
  792. X(defmacro bar (x) `'(global-bar-expanded ,x))
  793. X
  794. X(defun baz (&rest ignore) ())
  795. X
  796. X(take-it-out-for-a-test-walk (foo arg1 arg2 arg3))
  797. X(take-it-out-for-a-test-walk (foo (baz 1 2) (baz 3 4 5)))
  798. X
  799. X(take-it-out-for-a-test-walk (block block-name a b c))
  800. X(take-it-out-for-a-test-walk (block block-name (foo a) b c))
  801. X
  802. X(take-it-out-for-a-test-walk (catch catch-tag (foo a) b c))
  803. X(take-it-out-for-a-test-walk (compiler-let ((a 1) (b 2)) (foo a) b))
  804. X(take-it-out-for-a-test-walk (prog () (declare (special a b))))
  805. X(take-it-out-for-a-test-walk (let (a b c)
  806. X                               (declare (special a b))
  807. X                               (foo a) b c))
  808. X(take-it-out-for-a-test-walk (let (a b c)
  809. X                               (declare (special a) (special b))
  810. X                               (foo a) b c))
  811. X(take-it-out-for-a-test-walk (let (a b c)
  812. X                               (declare (special a))
  813. X                               (declare (special b))
  814. X                               (foo a) b c))
  815. X(take-it-out-for-a-test-walk (let (a b c)
  816. X                               (declare (special a))
  817. X                               (declare (special b))
  818. X                               (let ((a 1))
  819. X                                 (foo a) b c)))
  820. X(take-it-out-for-a-test-walk (eval-when ()
  821. X                               a
  822. X                               (foo a)))
  823. X(take-it-out-for-a-test-walk (eval-when (eval when load)
  824. X                               a
  825. X                               (foo a)))
  826. X(take-it-out-for-a-test-walk (progn (function foo)))
  827. X(take-it-out-for-a-test-walk (progn a b (go a)))
  828. X(take-it-out-for-a-test-walk (if a b c))
  829. X(take-it-out-for-a-test-walk (if a b))
  830. X(take-it-out-for-a-test-walk ((lambda (a b) (list a b)) 1 2))
  831. X(take-it-out-for-a-test-walk ((lambda (a b) (declare (special a)) (list a b))
  832. X                  1 2))
  833. X(take-it-out-for-a-test-walk (let ((a a) (b a) (c b)) (list a b c)))
  834. X(take-it-out-for-a-test-walk (let* ((a a) (b a) (c b)) (list a b c)))
  835. X(take-it-out-for-a-test-walk (let ((a a) (b a) (c b))
  836. X                               (declare (special a b))
  837. X                               (list a b c)))
  838. X(take-it-out-for-a-test-walk (let* ((a a) (b a) (c b))
  839. X                               (declare (special a b))
  840. X                               (list a b c)))
  841. X(take-it-out-for-a-test-walk (let ((a 1) (b 2))
  842. X                               (foo bar)
  843. X                               (declare (special a))
  844. X                               (foo a b)))
  845. X(take-it-out-for-a-test-walk (multiple-value-call #'foo a b c))
  846. X(take-it-out-for-a-test-walk (multiple-value-prog1 a b c))
  847. X(take-it-out-for-a-test-walk (progn a b c))
  848. X(take-it-out-for-a-test-walk (progv vars vals a b c))
  849. X(take-it-out-for-a-test-walk (quote a))
  850. X(take-it-out-for-a-test-walk (return-from block-name a b c))
  851. X(take-it-out-for-a-test-walk (setq a 1))
  852. X(take-it-out-for-a-test-walk (setq a (foo 1) b (bar 2) c 3))
  853. X(take-it-out-for-a-test-walk (tagbody a b c (go a)))
  854. X(take-it-out-for-a-test-walk (the foo (foo-form a b c)))
  855. X(take-it-out-for-a-test-walk (throw tag-form a))
  856. X(take-it-out-for-a-test-walk (unwind-protect (foo a b) d e f))
  857. X
  858. X
  859. X(take-it-out-for-a-test-walk (flet ((flet-1 (a b) (list a b)))
  860. X                               (flet-1 1 2)
  861. X                               (foo 1 2)))
  862. X(take-it-out-for-a-test-walk (labels ((label-1 (a b) (list a b)))
  863. X                               (label-1 1 2)
  864. X                               (foo 1 2)))
  865. X(take-it-out-for-a-test-walk (macrolet ((macrolet-1 (a b) (list a b)))
  866. X                               (macrolet-1 a b)
  867. X                               (foo 1 2)))
  868. X
  869. X(take-it-out-for-a-test-walk (macrolet ((foo (a) `(inner-foo-expanded ,a)))
  870. X                               (foo 1)))
  871. X
  872. X(take-it-out-for-a-test-walk (progn (bar 1)
  873. X                                    (macrolet ((bar (a)
  874. X                         `(inner-bar-expanded ,a)))
  875. X                                      (bar 1))))
  876. X
  877. X(take-it-out-for-a-test-walk (progn (bar 1)
  878. X                                    (macrolet ((bar (s)
  879. X                         (bar s)
  880. X                         `(inner-bar-expanded ,s)))
  881. X                                      (bar 2))))
  882. X
  883. X(take-it-out-for-a-test-walk (cond (a b)
  884. X                                   ((foo bar) a (foo a))))
  885. X
  886. X
  887. X(let ((the-lexical-variables ()))
  888. X  (walk-form '(let ((a 1) (b 2))
  889. X        #'(lambda (x) (list a b x y)))
  890. X         :walk-function #'(lambda (form context)
  891. X                (when (and (symbolp form)
  892. X                       (variable-lexical-p form))
  893. X                  (push form the-lexical-variables))
  894. X                form))
  895. X  (or (and (= (length the-lexical-variables) 3)
  896. X       (member 'a the-lexical-variables)
  897. X       (member 'b the-lexical-variables)
  898. X       (member 'x the-lexical-variables))
  899. X      (error "Walker didn't do lexical variables of a closure properly.")))
  900. X
  901. X|#
  902. X
  903. X()
  904. X
  905. END_OF_FILE
  906. if test 33372 -ne `wc -c <'walk.l'`; then
  907.     echo shar: \"'walk.l'\" unpacked with wrong size!
  908. fi
  909. # end of 'walk.l'
  910. fi
  911. echo shar: End of archive 9 \(of 13\).
  912. cp /dev/null ark9isdone
  913. MISSING=""
  914. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  915.     if test ! -f ark${I}isdone ; then
  916.     MISSING="${MISSING} ${I}"
  917.     fi
  918. done
  919. if test "${MISSING}" = "" ; then
  920.     echo You have unpacked all 13 archives.
  921.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  922. else
  923.     echo You still need to unpack the following archives:
  924.     echo "        " ${MISSING}
  925. fi
  926. ##  End of shell archive.
  927. exit 0
  928. -- 
  929.  
  930. Rich $alz            "Anger is an energy"
  931. Cronus Project, BBN Labs    rsalz@bbn.com
  932. Moderator, comp.sources.unix    sources@uunet.uu.net
  933.